
package fr.n7.khome.view;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.TableColumnModelEvent;
import javax.swing.event.TableColumnModelListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;

import fr.n7.khome.core.Request;
import fr.n7.khome.model.LodgingFieldName;

public class KHomeRequestTableModel<Requests extends List<Request>>
extends AbstractTableModel
implements TableModelListener, TableColumnModelListener{

	private static final long serialVersionUID = 4444296788572537283L;
	private Vector<Vector<Object>> nonEditableColumns;
	private Vector<LodgingFieldName> editableColumns;
	private Map<LodgingFieldName, Integer> fieldNameToImportance = new HashMap<LodgingFieldName, Integer>();
	private String[] columnNames;

	private Requests requests;
	private KHomeTable table;
	private KHomeTable resultsTable;

	private float maxGLikelihood;

	public KHomeRequestTableModel(String[] columnNames, Requests requests, KHomeTable table, KHomeTable resultsTable){
		super();

		this.columnNames = columnNames;
		this.table = table;

		nonEditableColumns = new Vector<Vector<Object>>();
		Vector<Object> col1 = new Vector<Object>();
		col1.add("Importances:");
		col1.add("Pattern:");
		nonEditableColumns.add(col1);

		editableColumns = new Vector<LodgingFieldName>();
		editableColumns.add(LodgingFieldName.TYPE);
		editableColumns.add(LodgingFieldName.PRICE);
		editableColumns.add(LodgingFieldName.LIVE_SURFACE);
		editableColumns.add(LodgingFieldName.FIELD_SURFACE);
		editableColumns.add(LodgingFieldName.AGE);
		editableColumns.add(LodgingFieldName.WORKPRICEPC);

		fieldNameToImportance = new HashMap<LodgingFieldName, Integer>();

		this.requests = requests;
		this.resultsTable = resultsTable;
	}

	public int getColumnCount() {
		return nonEditableColumns.size()+editableColumns.size();
	}

	public int getRowCount() {
		return requests.size();
	}

	public String getColumnName(int col) {
		return columnNames[col];
	}

	public Object getValueAt(int row, int col) {
		int d = nonEditableColumns.size();
		if(col < d){
			return nonEditableColumns.get(col).get(row);
		}else{
			col = col-d;
			if(row == 0){
				return requests.get(row).getFieldImportance(editableColumns.get(col));
			}else if(row == 1){
				return requests.get(row).getField(editableColumns.get(col));
			}
		}
		return null;
	}

	/*
	 * JTable uses this method to determine the default renderer/
	 * editor for each cell.  If we didn't implement this method,
	 * then the last column would contain text ("true"/"false"),
	 * rather than a check box.
	 */
	public Class getColumnClass(int c) {
		return getValueAt(0, c).getClass();
	}

	/*
	 * Don't need to implement this method unless your table's
	 * editable.
	 */
	public boolean isCellEditable(int row, int col) {
		//Note that the data/cell address is constant,
		//no matter where the cell appears onscreen.
		int d = nonEditableColumns.size();
		if(col < d){
			return false;
		}else{
			return true;
		}
	}

	/*
	 * Don't need to implement this method unless your table's
	 * data can change.
	 */
	public void setValueAt(Object value, int row, int col) {
		int d = nonEditableColumns.size();
		if(col >= d){
			col = col-d;
			if(row == 0){
				requests.get(row).setFieldImportance(editableColumns.get(col), (Integer)value);
			}else if(row == 1){
				requests.get(row).setField(editableColumns.get(col), value);
			}
		}
		fireTableCellUpdated(row, col);
	}

	@Override
	public void tableChanged(TableModelEvent tme) {
		if(fieldNameToImportance.isEmpty()){
			majImportances();
		}
		if(tme.getType() == TableModelEvent.UPDATE){
			int col = tme.getColumn();
			int firstRow = tme.getFirstRow();
			int lastRow = tme.getLastRow();
			if(col != TableModelEvent.ALL_COLUMNS && firstRow == lastRow){
				int row = firstRow;
				if(row < requests.size()){
					((KHomeResultTableModel)resultsTable.getModel()).updateResultsWithRequests(requests);
				}
			}
		}
	}

	public Requests getRequests() {
		return requests;
	}

	@Override
	public void columnAdded(TableColumnModelEvent e) {}

	@Override
	public void columnMarginChanged(ChangeEvent e) {
		Enumeration<TableColumn> columnEnum = resultsTable.getColumnModel().getColumns();
		while(columnEnum.hasMoreElements()){
			TableColumn column = columnEnum.nextElement();
			int index = resultsTable.getColumnModel().getColumnIndex(column.getIdentifier());
			column.setPreferredWidth(table.getColumnModel().getColumn(index).getPreferredWidth());
		}
	}

	@Override
	public void columnMoved(TableColumnModelEvent e) {
		int fromIndex = e.getFromIndex();
		int toIndex = e.getToIndex();
		if(fromIndex != toIndex){
			int from = table.convertColumnIndexToModel(fromIndex);
			int to = table.convertColumnIndexToModel(toIndex);
			int rfrom = resultsTable.convertColumnIndexToModel(fromIndex);
			int rto = resultsTable.convertColumnIndexToModel(toIndex);
			if(from != rfrom || to != rto){
				resultsTable.getColumnModel().moveColumn(e.getFromIndex(), e.getToIndex());
			}
		}
	}

	public boolean majImportances(){
		boolean modified = false;
		for(int i=0; i<editableColumns.size(); i++){
			modified |= fieldNameToImportance.put(
					editableColumns.get(table.convertColumnIndexToModel(i)),
					10-i)
					!= null;
		}
		return modified;
	}

	public float getMaxGLikelyhood(){
		return maxGLikelihood;
	}

	@Override
	public void columnRemoved(TableColumnModelEvent e) {}

	@Override
	public void columnSelectionChanged(ListSelectionEvent e) {}
}
